#include "ParaboleC.hpp"

/*
 * Parabole z ograniczeniami x_(i+1) + x_i >= 2
 * Gdy n nieparzyste, ostatnie ograniczenie ma trzy zmienne
 *
 */

ParaboleC::ParaboleC(Index dimension) :
	BlockConstrainedProblem(dimension) {
}

bool ParaboleC::get_blocks_indexes(Index n, Index m, Index procCount,
		Index* procStartIndex) {
	//mozna przydzielac wielokrotnosci dwoch zmiennych na blok
	int restrMean = n / 2 / procCount;
	procStartIndex[0] = 0;
	for (int p = 1; p < procCount; ++p) {
		procStartIndex[p] = restrMean;
	}
	for (int p = 1; p <= (n / 2) % procCount; ++p) {
		procStartIndex[p]++;
	}

	//w procStartIndex ilosc ograniczen
	int restrDist = 0;
	for (int p = 1; p < procCount; ++p) {
		restrDist += procStartIndex[p];
		procStartIndex[p] = restrDist * 2;
	}

	return true;
}

bool ParaboleC::get_nlp_info(Index& n, Index& m, Index& nnz_jac_g,
		Index& nnz_h_lag) {
	n = dimension;
	m = dimension / 2;
	nnz_jac_g = n;
	nnz_h_lag = 0;

	return true;
}

bool ParaboleC::get_bounds_info(Index m, Number* g_l, Number* g_u) {
	for (int i = 0; i < m; ++i) {
		g_l[i] = 2;
		g_u[i] = 1e19;
	}

	return true;
}

bool ParaboleC::get_starting_point(Index n, Number* x) {
	for (Index i = 0; i < n; ++i) {
		x[i] = 3;
	}

	return true;
}

bool ParaboleC::eval_f(Index n, const Number* x, bool new_x, Number& obj_value) {
	Number sum = 0;
	for (int i = 0; i < n; ++i) {
		sum += x[i] * x[i];
	}
	obj_value = sum;

	return true;
}

bool ParaboleC::eval_grad_f(Index n, const Number* x, bool new_x,
		Number* grad_f) {
	for (int i = 0; i < n; ++i) {
		grad_f[i] = 2 * x[i];
	}
	return true;
}

bool ParaboleC::eval_g(Index n, const Number* x, bool new_x, Index m, Number* g) {
	for (Index i = 0; i < m; i++) {
		g[i] = x[i * 2] + x[i * 2 + 1];
	}
	if (n % 2 == 1) {
		g[m - 1] += x[n - 1];
	}
	return true;
}

bool ParaboleC::eval_jac_g(Index n, const Number* x, bool new_x, Index m,
		Index nele_jac, Index* iRow, Index *jCol, Number* values) {
	if (values == NULL) {
		//struktura
		Index jac_index = 0;
		for (Index i = 0; i < m; i++) {
			iRow[jac_index] = iRow[jac_index + 1] = i;
			jCol[jac_index] = 2 * i;
			jCol[jac_index + 1] = 2 * i + 1;
			jac_index += 2;
		}

		if (n % 2 == 1) {
			iRow[jac_index] = m - 1;
			jCol[jac_index++] = n - 1;
		}

		assert(jac_index == nele_jac && "nie wszystko wypelnione!");
	} else {
		for (Index i = 0; i < nele_jac; i++) {
			values[i] = 1;
		}
	}
	return true;
}

